package cate.game.activity.luckybag;

import cate.common.table.activity.luckybag.row.LuckyBagExchangeRow;
import cate.common.table.activity.luckybag.row.LuckyBagRow;
import cate.common.table.activity.luckybag.row.RewardPoolRow;
import cate.common.table.activity.luckybag.row.ScoreRewardRow;
import cate.common.table.d.GDObj;
import cate.common.table.d.GDOperation;
import cate.common.util.GameResult;
import cate.common.util.random.RWList;
import cate.game.activity.base.core.RoleActivitySingle;
import cate.game.activity.luckybag.msg.LuckyBagActivitGlobalDataResp;
import cate.game.activity.luckybag.msg.LuckyBagActivityInfoResp;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class LuckyBagActivity extends RoleActivitySingle {
    @NoteField("活动期间充值金额")
    public long paySum;
    @NoteField("个人福气积分")
    public long score;
    @NoteField("当前要开启哪一层")
    public int floor;
    @NoteField("每一层的数据")
    public Map<Integer, LuckyBagPo> bagPoMap;
    @NoteField("全服积分领取记录")
    public Map<Integer, Boolean> scoreRecord;
    @NoteField("福气积分兑换记录")
    public Map<Integer, Integer> buyRecord;
    @NoteField("领奖记录")
    public List<LuckyBagLog> takeLog;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (takeLog == null) {
            takeLog = new ArrayList<>();
        }
        if (scoreRecord == null) {
            scoreRecord = new HashMap<>();
        }
        if (buyRecord == null) {
            buyRecord = new HashMap<>();
        }
        if (bagPoMap == null) {
            bagPoMap = new HashMap<>();
        }
        bagPoMap.values().forEach(bag -> bag.initialize(this));
        role.getActivity().registerRecharge(this, this::onPay);
    }

    public void onPay(long payNum) {
        paySum += payNum;
        noticeUpdate();
    }

    public void noticeUpdate() {
        role.sendNow(new LuckyBagActivityInfoResp(this));
        LuckyBagActivityHandler handler = role.getGame().activityGlobal.getEnableHandler(funcId());
        role.sendNow(new LuckyBagActivitGlobalDataResp(handler.getGlobalData()));
    }

    //开福袋
    public GameResult<LuckyBagActivity> openBag(int floor, int pos) {
        GameResult<LuckyBagActivity> r = new GameResult<>();
        r.data = this;
        LuckyBagRow row = findRow(floor);
        if (row == null) {
            return r.fail("找不到配置");
        }
        if (floor != this.floor) {
            return r.fail("请先开启上一层");
        }
        if (bagPoMap.get(floor) == null) {
            return r.fail("找不到本层");
        }
        if (bagPoMap.get(floor).isDrawn) {
            return r.fail("本层福袋已开启");
        }
        if (pos <= 0 || pos > row.bagNum) {
            return r.fail("福袋不存在");
        }
        MixRes cost = new MixRes(row.cost);
        GameResult<MixResItem> consume = cost.consume(role);
        if (!consume.ok()) {
//            role.getGame().notice.tipResItem(role,consume.data);
            return r.fail(consume);
        }
        bagPoMap.get(floor).drawTimes++;
        //抽取
        int id = draw(row, bagPoMap.get(floor));
        bagPoMap.get(floor).setReward(pos, id);
        this.floor++;
        //添加个人积分
        MixRes score = new MixRes(row.singleScore);
        score.add(role, false, GDOperation.LUCKY_BAG);
        LuckyBagActivityHandler handler = role.getGame().activityGlobal.getEnableHandler(funcId());
        handler.addScore(row.globalScore);
        score.addItem(new MixResItem(GDObj.Type.NUM, row.globalId, row.globalScore));
        role.getGame().notice.dialogReward(role, score);
        role.getGame().role.activeForOnline(role -> {
            role.sendNow(new LuckyBagActivitGlobalDataResp(handler.getGlobalData()));
        });
        return r;
    }

    private int draw(LuckyBagRow row, LuckyBagPo bagPo) {
        if (row.cheatNum > 0 && bagPo.drawTimes >= row.cheatNum) {
            bagPo.drawTimes = 0;
            return row.cheatItem;
        }
        int group;
        if (paySum >= row.recharge) {
            group = row.rechargePool;
        } else {
            group = row.normalPoolId;
        }
        RWList<RewardPoolRow> pool = createPoolByGroup(group);
        RewardPoolRow rewardRow = pool.get();
        return rewardRow.id;
    }

    public GameResult<LuckyBagActivity> takeReward(int floor) {
        GameResult<LuckyBagActivity> r = new GameResult<>();
        r.data = this;
        LuckyBagPo luckyBagPo = bagPoMap.get(floor);
        if (luckyBagPo == null) {
            return r.fail("领取的福袋不存在");
        }
        if (!luckyBagPo.isDrawn || luckyBagPo.rewardMap.isEmpty()) {
            return r.fail("本层奖励未抽取");
        }
        MixRes reward = luckyBagPo.createReward();
        reward.addAndDialog(role, true, GDOperation.LUCKY_BAG);
        this.floor = 1;
        //领取奖励后重置福袋。
        bagPoMap.values().forEach(LuckyBagPo::reset);
        LuckyBagLog log = new LuckyBagLog(role.getGame().config.srvId, reward, role.getGame().time.now());
        takeLog.add(0, log);
        if (takeLog.size() > 20) {
            takeLog.remove(takeLog.size() - 1);
        }
        return r;
    }

    public GameResult<LuckyBagActivity> takeScoreReward(int tid) {
        GameResult<LuckyBagActivity> r = new GameResult<>();
        r.data = this;
        ScoreRewardRow scoreRow = findScoreRow(tid);
        if (scoreRow == null) {
            return r.fail("配置不存在");
        }
        if (scoreRecord.containsKey(tid) && scoreRecord.get(tid)) {
            return r.fail("奖励已领取");
        }
        if (scoreRow.group != scoreGroup()) {
            return r.fail("非本期奖励");
        }
        if (paySum < scoreRow.payLimit) {
            return r.fail("您的充值未达标");
        }
        LuckyBagActivityHandler handler = role.getGame().activityGlobal.getEnableHandler(funcId());

        if (handler.getScore() < scoreRow.scoreLimit) {
            return r.fail("全服积分未达标");
        }
        MixRes reward = new MixRes(scoreRow.reward);
        reward.addAndDialog(role, true, GDOperation.LUCKY_BAG_SCORE, tid);
        scoreRecord.put(tid, true);
        return r;
    }

    public GameResult<LuckyBagActivity> buyItem(int tid, int num) {
        GameResult<LuckyBagActivity> r = new GameResult<>();
        r.data = this;
        if (num <= 0) {
            return r.fail("数量不合法");
        }
        if (!buyRecord.containsKey(tid)) {
            return r.fail("找不到配置1");
        }
        LuckyBagExchangeRow exchangeRow = findExchangeRow(tid);
        if (exchangeRow == null) {
            return r.fail("找不到配置2");
        }
        int curNum = buyRecord.get(tid);
        if (exchangeRow.limit != -1 && num > exchangeRow.limit - curNum) {
            return r.fail("兑换次数不足");
        }
        MixRes consumeRes = new MixRes(exchangeRow.cost);
        if (consumeRes.isEmpty()) {
            return r.fail("消耗配置错误");
        }
        consumeRes.items.forEach(item -> item.num *= num);
        MixRes rewardRes = new MixRes(exchangeRow.reward);
        if (rewardRes.isEmpty()) {
            return r.fail("奖励配置错误");
        }
        int itemId = role.getGame().table.luckyBag.luckyBag.getItemId(configTid());
        int materialCost = (int) consumeRes.count(GDObj.Type.NUM, itemId);
        consumeRes.items.removeIf(item -> item.type == GDObj.Type.NUM && item.tid == itemId);
        if (!consumeRes.isEmpty()) {
            role.log.setOperation(GDOperation.LUCKY_BAG_EXCHANGE, tid);
            EcResult<?> r_res = consumeRes.consume(role);
            role.log.clearOperation();
            if (!r_res.ok()) {
                return r.fail(r_res.message);
            }
        }
        if (materialCost > 0) {
            EcResult<Void> r_material = changeScoreNum(-materialCost);
            if (!r_material.ok()) {
                return r.fail(r_material.message);
            }
        }
        buyRecord.put(tid, curNum + num);
        rewardRes.items.forEach(item -> item.num *= num);
        rewardRes.addAndDialog(role, true, GDOperation.LUCKY_BAG_EXCHANGE, tid);
        return r;
    }

    private EcResult<Void> changeScoreNum(long num) {
        EcResult<Void> r = new EcResult<>();
        if (num < 0 && score + num < 0) {
            return r.fail("材料数量不足");
        }
        score += num;
        return r.success();
    }

    @Override
    public void onEnter() {
        super.onEnter();
        if (floor == 0) {
            floor = 1;
        }
    }

    @Override
    public void onRoleOpen() {
        this.floor = 1;
    }

    @Override
    public void onRoleEnd() {
        paySum = 0;
        score = 0;
        bagPoMap.clear();
        buyRecord.clear();
        scoreRecord.clear();
        takeLog.clear();
    }

    @Override
    public void initSend() {
        noticeUpdate();
    }

    @Override
    public void excelCheck() {
        initBagMap();
        initBuyRecord();
    }

    private void initBuyRecord() {
        if (exchangeGroup() != 0) {
            Map<Integer, LuckyBagExchangeRow> rowMap = findExchangeRows(exchangeGroup()).stream().collect(Collectors.toMap(row -> row.id, row -> row));
            if (rowMap.isEmpty()) {
                buyRecord.clear();
                return;
            }
            buyRecord.entrySet().removeIf(kv -> !rowMap.containsKey(kv.getKey()));
            for (LuckyBagExchangeRow config : rowMap.values()) {
                if (!buyRecord.containsKey(config.id)) {
                    buyRecord.put(config.id, 0);
                }
            }
        }
    }

    private void initBagMap() {
        Map<Integer, LuckyBagRow> luckyBagRowMap = findRows().stream().collect(Collectors.toMap(row -> row.floor, row -> row));
        if (luckyBagRowMap.isEmpty()) {
            bagPoMap.clear();
            return;
        }
        bagPoMap.entrySet().removeIf(kv -> !luckyBagRowMap.containsKey(kv.getKey()));
        for (LuckyBagRow config : luckyBagRowMap.values()) {
            if (!bagPoMap.containsKey(config.floor)) {
                LuckyBagPo bagPo = new LuckyBagPo();
                bagPo.initialize(this);
                bagPoMap.put(config.floor, bagPo);
            }
        }
    }

    public void addScore(long num) {
        score += num;
        LuckyBagActivityHandler handler = role.getGame().activityGlobal.getEnableHandler(funcId());
        handler.addScore(num);
        noticeUpdate();
    }

    public void addNumByItem(int tid, long num) {
        int itemId = role.getGame().table.luckyBag.luckyBag.getItemId(configTid());
        if (itemId == 0 || tid != itemId) {
            return;
        }
        changeScoreNum(num);
    }

    public int exchangeGroup() {
        return findRows().stream().mapToInt(row -> row.exchangeGroup).findAny().orElse(0);
    }

    public int scoreGroup() {
        return findRows().stream().mapToInt(row -> row.scoreRewardGroup).findAny().orElse(0);
    }

    public List<LuckyBagRow> findRows() {
        return role.getGame().table.luckyBag.luckyBag.getRowsByConfigId(configTid());
    }

    public LuckyBagRow findRow(int floor) {
        return role.getGame().table.luckyBag.luckyBag.getRowsByConfigId(configTid()).stream().filter(row -> row.floor == floor).findAny().orElse(null);
    }

    public RWList<RewardPoolRow> createPoolByGroup(int group) {
        return role.getGame().table.luckyBag.rewardPool.createPoolByGroup(group);
    }

    public RewardPoolRow findRewardRow(int tid) {
        return role.getGame().table.luckyBag.rewardPool.get(tid);
    }

    public ScoreRewardRow findScoreRow(int tid) {
        return role.getGame().table.luckyBag.scoreReward.get(tid);
    }

    public LuckyBagExchangeRow findExchangeRow(int tid) {
        return role.getGame().table.luckyBag.exchange.get(tid);
    }

    public List<LuckyBagExchangeRow> findExchangeRows(int group) {
        return role.getGame().table.luckyBag.exchange.getRowsByGroup(group);
    }
}
